﻿using System;

namespace GLib
{
    public class BufferPool
    {
        public const uint INIT_SIZE = 1024;

        public const  uint POOL_COUNT = 1000;

        public const uint INC_COUNT = 100;

        private bool[] m_used;

        private int lastUsedIndex;
        private uint curCount;
        private uint totalCount;

        private byte[][] m_pMem;

        public BufferPool()
        {
            m_pMem = new byte[POOL_COUNT][];
            m_used = new bool[POOL_COUNT];

            for (int i = 0; i < POOL_COUNT; i++)
            {
                m_pMem[i] = new byte[INIT_SIZE];
            }

            lastUsedIndex = -1;
            curCount = 0;
            totalCount = POOL_COUNT;
        }

        private int GetNextUnusedIndex()
        {
            lastUsedIndex++;
            if (lastUsedIndex >= totalCount)
            {
                lastUsedIndex = 0;
            }

            while (m_used[lastUsedIndex])
            {
                lastUsedIndex++;

                if (lastUsedIndex >= totalCount)
                {
                    lastUsedIndex = 0;
                }
            }

            return lastUsedIndex;
        }

        private void IncPool()
        {
            totalCount = totalCount + INC_COUNT;

            byte[][] _pMem = new byte[totalCount][];
            bool[] _used = new bool[totalCount];

            for (uint i = 0; i < totalCount; i++)
            {
                if (i >= totalCount - INC_COUNT)
                {
                    _pMem[i] = new byte[INIT_SIZE];
                }
                else
                {
                    _pMem[i] = m_pMem[i];
                }
            }

            for (uint i = 0; i < totalCount; i++)
            {
                if (i >= totalCount - INC_COUNT)
                {
                    _used[i] = false;
                }
                else
                {
                    _used[i] = m_used[i];
                }
            }

            m_pMem = _pMem;
            m_used = _used;
        }

        public int GetBufferIndex()
        {
            if (curCount < totalCount)
            {
                curCount++;

                GetNextUnusedIndex();

                return lastUsedIndex;
            }
            else
            {
                IncPool();

                curCount++;

                GetNextUnusedIndex();

                return lastUsedIndex;
            }
        }

        public byte[] GetBuffer(uint index)
        {
            return m_pMem[index];
        }


        public void FreeBuffer(uint index)
        {
            if (index < totalCount)
            {
                curCount--;
                m_used[index] = false;
            }
        }
    }
}
